
package myjson

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strconv"
)

func NewError(format string, a ...interface{}) error {
	return errors.New(fmt.Sprintf(format, a...))
}

func Type(value interface{}) reflect.Type {
	return reflect.TypeOf(value)
}

func ToString(value interface{}) (string, error) {
	switch v := value.(type) {
	case string:
		return v, nil
	case int, int8, int16, int32, int64:
		n, err := ToInt64(v)
		if err != nil{
			return "", err
		}
		return strconv.FormatInt(n, 10), nil
	case uint, uint8, uint16, uint32, uint64:
		n, err := ToInt64(v)
		if err != nil{
			return "", err
		}
		return strconv.FormatUint(uint64(n), 10), nil
	case float64:
		return strconv.FormatFloat(v, 'f', -1, 64), nil
	case float32:
		return strconv.FormatFloat(float64(v), 'f', -1, 32), nil
	case map[string]interface{}, []interface{}:
		b , err := json.Marshal(v)
		return string(b), err
	case []byte:
		return string(v), nil
	default:
		return fmt.Sprintf("%v", v), nil
	}
	return "", NewError("ToString value type error: %v", Type(value))
}

func ToFloat64(value interface{})(float64, error) {
	switch v := value.(type) {
	case int:
		return float64(v), nil
	case int8:
		return float64(v), nil
	case int16:
		return float64(v), nil
	case int32:
		return float64(v), nil
	case int64:
		return float64(v), nil
	case uint:
		return float64(v), nil
	case uint8:
		return float64(v), nil
	case uint16:
		return float64(v), nil
	case uint32:
		return float64(v), nil
	case uint64:
		return float64(v), nil
	case float32:
		return float64(v), nil
	case float64:
		return float64(v), nil
	case string:
		return strconv.ParseFloat(v, 64)
	case []byte:
		return strconv.ParseFloat(string(v), 64)
	default:
		switch value := reflect.ValueOf(v); value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			n := value.Int()
			return float64(n), nil
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			n := value.Uint()
			return float64(n), nil
		case reflect.Float64, reflect.Float32:
			return value.Float(), nil
		case reflect.String:
			return strconv.ParseFloat(value.String(), 64)
		case reflect.Slice:
			return strconv.ParseFloat(string(value.Bytes()), 64)
		}
	}
	return 0, NewError("ToFloat64 value type error: %v", Type(value))
}

func ToFloat32(value interface{})(float32, error)  {
	v, err := ToFloat64(value)
	return float32(v), err
}

func ToInt64(value interface{}) (int64, error){
	switch n := value.(type) {
	case int:
		return int64(n), nil
	case int8:
		return int64(n), nil
	case int16:
		return int64(n), nil
	case int32:
		return int64(n), nil
	case int64:
		return int64(n), nil
	case uint:
		return int64(n), nil
	case uint8:
		return int64(n), nil
	case uint16:
		return int64(n), nil
	case uint32:
		return int64(n), nil
	case uint64:
		return int64(n), nil
	case float64:
		return int64(n), nil
	case float32:
		return int64(n), nil
	case string:
		f, err := strconv.ParseFloat(n, 64)
		return int64(f), err
	case []byte:
		f, err := strconv.ParseFloat(string(n), 64)
		return int64(f), err
	default:
		switch value := reflect.ValueOf(n); value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			return value.Int(), nil
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
			return int64(value.Uint()), nil
		case reflect.Float64, reflect.Float32:
			return int64(value.Float()), nil
		case reflect.String:
			return strconv.ParseInt(value.String(), 10, 64)
		case reflect.Slice:
			return strconv.ParseInt(string(value.Bytes()), 10, 64)
		}
	}
	return 0, NewError("ToInt64 value type error: %v", Type(value))
}

func ToInt32(value interface{}) (int32, error) {
	v ,err := ToInt64(value)
	return int32(v), err
}

func ToInt16(value interface{}) (int16, error) {
	v ,err := ToInt64(value)
	return int16(v), err
}

func ToInt8(value interface{}) (int8, error) {
	v ,err := ToInt64(value)
	return int8(v), err
}

func ToInt(value interface{}) (int, error) {
	v ,err := ToInt64(value)
	return int(v), err
}

func ToUint64(value interface{}) (uint64, error){
	v ,err := ToInt64(value)
	return uint64(v), err
}

func ToUint32(value interface{}) (uint32, error){
	v ,err := ToInt64(value)
	return uint32(v), err
}

func ToUint16(value interface{}) (uint16, error){
	v ,err := ToInt64(value)
	return uint16(v), err
}

func ToUint8(value interface{}) (uint8, error){
	v ,err := ToInt64(value)
	return uint8(v), err
}

func ToUint(value interface{}) (uint, error){
	v ,err := ToInt64(value)
	return uint(v), err
}